<script setup lang="ts">
import { ref, reactive } from 'vue'
import { NText, useNotification, NModal, NCard, NSpace, NTag, NButton, NTabs, NTabPane, NIcon, NForm, NGrid, NFormItemGi, NFormItem, NInput, NInputNumber, NMention, NAutoComplete, NDynamicInput, NDynamicTags, NSelect, NTreeSelect, NCascader, NCheckboxGroup, NCheckbox, NRadioGroup, NRadio, NRadioButton, NSwitch, NDatePicker, NTimePicker, NSlider, NTransfer, NRate, NColorPicker, NUpload, NDivider } from 'naive-ui'

import { CopyOutlined, DeleteOutlined } from '@vicons/antd'

import http from '@/tools/http'

const notification = useNotification()

type formDataType = {
    title: string
    model: string
    rules: string
    width: number
    size: any
    labelAlign: any
    labelPlacement: any
    labelWidth: number
    xGap: number
}

type optionType = {
    label: string
    value: string
}

type formItemDataType = {
    id: number
    type: string
    dataType: string
    name: string
    label: string
    placeholder: string,
    getData: Function
    options?: optionType[]
    data: any
    span: number
    disable: boolean
    required: boolean
    verifyRegex: string
    verifyErrMsg: string
    isMouseenter: boolean
    isSelected: boolean
    isDragging: boolean
}

const formConfig = reactive<formDataType>({
    title: "表单标题",
    model: "formData",
    rules: "formRules",
    width: 500,
    size: "medium",
    labelAlign: "right",
    labelPlacement: "left",
    labelWidth: 100,
    xGap: 0
})

const componentGroupList = reactive([{
    name: "输入型组件",
    componentList: [{
        name: "文本输入",
        defaultData: {
            id: 1,
            name: "input",
            type: "input",
            dataType: "string",
            label: "文本输入",
            placeholder: "请输入",
            data: "",
            span: 24,
            disable: false,
            required: false,
            verifyRegex: "",
            verifyErrMsg: "请输入",
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "数字输入",
        defaultData: {
            id: 1,
            name: "inputNumber",
            type: "input-number",
            dataType: "number",
            label: "数字输入",
            placeholder: "请输入",
            data: 0,
            span: 24,
            disable: false,
            required: false,
            verifyRegex: "",
            verifyErrMsg: "请输入",
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "提及",
        defaultData: {
            id: 1,
            name: "montion",
            type: "montion",
            dataType: "string",
            label: "提及",
            placeholder: "请输入",
            options: [
                { label: "AAA公司", value: "AAA公司" },
                { label: "BBB公司", value: "BBB公司" },
                { label: "CCC公司", value: "CCC公司" }
            ],
            data: "",
            span: 24,
            verifyErrMsg: "请输入",
            disable: false,
            required: false,
            verifyRegex: "",
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "自动填充",
        defaultData: {
            id: 1,
            name: "autoComplete",
            type: "auto-complete",
            dataType: "string",
            label: "自动填充",
            placeholder: "请输入",
            getData: (prefix: string): optionType[] => {
                return ['@gmail.com', '@163.com', '@qq.com'].map((suffix) => {
                    return {
                        label: prefix + suffix,
                        value: prefix + suffix
                    }
                })
            },
            options: [
                { label: "@gmail.com", value: "@gmail.com" },
                { label: "@163.com", value: "@163.com" },
                { label: "@qq.com", value: "@qq.com" },
            ],
            data: "",
            span: 24,
            disable: false,
            required: false,
            verifyRegex: "",
            verifyErrMsg: "请输入",
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "动态录入",
        defaultData: {
            id: 1,
            name: "dynamicInput",
            type: "dynamic-input",
            dataType: "Array<any>",
            label: "动态录入",
            placeholder: "请输入",
            data: [],
            span: 24,
            verifyErrMsg: "请输入",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "动态标签",
        defaultData: {
            id: 1,
            name: "dynamicTags",
            type: "dynamic-tags",
            dataType: "Array<any>",
            label: "动态标签",
            placeholder: "请输入",
            data: ['教师', '程序员'],
            span: 24,
            disable: false,
            required: false,
            verifyErrMsg: "请输入",
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }]
}, {
    name: "选择型组件",
    componentList: [{
        name: "选择器",
        defaultData: {
            id: 1,
            name: "select",
            type: "select",
            dataType: "string",
            label: "选择型组件",
            placeholder: "请选择",
            options: [
                { label: "男", value: "男" },
                { label: "女", value: "女" },
                { label: "其他", value: "其他" }
            ],
            data: "",
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "树形选择",
        defaultData: {
            id: 1,
            name: "treeSelect",
            type: "tree-select",
            dataType: "string",
            label: "树形选择",
            placeholder: "请选择",
            options: [
                { label: "AAA公司", value: "AAA公司" },
                { label: "BBB公司", value: "BBB公司" },
                { label: "CCC公司", value: "CCC公司" }
            ],
            data: "",
            verifyErrMsg: "请选择",
            span: 24,
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "级联选择",
        defaultData: {
            id: 1,
            name: "cascader",
            type: "cascader",
            dataType: "string",
            label: "级联选择",
            placeholder: "请选择",
            options: [
                { label: "AAA公司", value: "AAA公司" },
                { label: "BBB公司", value: "BBB公司" },
                { label: "CCC公司", value: "CCC公司" }
            ],
            data: "",
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "开关",
        defaultData: {
            id: 1,
            name: "switch",
            type: "switch",
            dataType: "string",
            label: "开关",
            placeholder: "请选择",
            data: true,
            span: 24,
            disable: false,
            verifyErrMsg: "请选择",
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "复选框",
        defaultData: {
            id: 1,
            name: "checkbox",
            type: "checkbox",
            dataType: "string",
            label: "复选框",
            placeholder: "请选择",
            data: true,
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "单选框",
        defaultData: {
            id: 1,
            name: "radio",
            type: "radio",
            dataType: "boolean",
            label: "单选框",
            placeholder: "请选择",
            data: true,
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "复选组",
        defaultData: {
            id: 1,
            name: "checkboxGroup",
            type: "checkbox-group",
            dataType: "Array<any>",
            label: "复选组",
            placeholder: "请选择",
            options: [
                { label: "北京", value: "北京" },
                { label: "上海", value: "上海" },
                { label: "深圳", value: "深圳" }
            ],
            data: [],
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "单选组",
        defaultData: {
            id: 1,
            name: "radioGroup",
            type: "radio-group",
            dataType: "string",
            label: "单选组",
            placeholder: "请选择",
            options: [
                { label: "北京", value: "北京" },
                { label: "上海", value: "上海" },
                { label: "深圳", value: "深圳" }
            ],
            data: "",
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "日期选择器",
        defaultData: {
            id: 1,
            name: "datePicker",
            type: "date-picker",
            dataType: "string",
            label: "日期选择器",
            placeholder: "请选择",
            data: null,
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "时间选择",
        defaultData: {
            id: 1,
            name: "timePicker",
            type: "time-picker",
            dataType: "string",
            label: "时间选择",
            placeholder: "请选择",
            data: null,
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "滑动选择",
        defaultData: {
            id: 1,
            name: "slider",
            type: "slider",
            dataType: "number",
            label: "滑动选择",
            placeholder: "请选择",
            data: 50,
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "穿梭框",
        defaultData: {
            id: 1,
            name: "transfer",
            type: "transfer",
            dataType: "Array<any>",
            label: "穿梭框",
            placeholder: "请输入transfer",
            options: [{
                label: "羊腿抓饭",
                value: "羊腿抓饭"
            }, {
                label: "碎肉抓饭",
                value: "碎肉抓饭"
            }, {
                label: "羊排抓饭",
                value: "羊排抓饭"
            }, {
                label: "素抓饭",
                value: "素抓饭"
            }, {
                label: "皮牙子",
                value: "皮牙子"
            }],
            data: [],
            span: 24,
            verifyErrMsg: "请选择",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "评分",
        defaultData: {
            id: 1,
            name: "rate",
            type: "rate",
            dataType: "number",
            label: "评分",
            placeholder: "请评分",
            data: 3,
            span: 24,
            verifyErrMsg: "请评分",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "颜色选择器",
        defaultData: {
            id: 1,
            name: "colorPicker",
            type: "color-picker",
            dataType: "string",
            label: "颜色选择器",
            placeholder: "请选择颜色",
            data: "#C37CD9FF",
            verifyErrMsg: "请选择颜色",
            span: 24,
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }]
}, {
    name: "其他组件",
    componentList: [{
        name: "上传",
        defaultData: {
            id: 1,
            name: "upload",
            type: "upload",
            dataType: "string",
            label: "上传",
            placeholder: "请选择文件",
            data: "",
            span: 24,
            verifyErrMsg: "请选择文件",
            disable: false,
            required: false,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }, {
        name: "按钮",
        defaultData: {
            id: 1,
            name: "button",
            type: "button",
            dataType: "string",
            label: "按钮",
            path: "button",
            placeholder: "",
            data: "input",
            span: 24,
            isMouseenter: false,
            isSelected: false,
            dragging: false
        }
    }]
}])

const formItemList = reactive<formItemDataType[]>([{
    id: 1,
    type: "input",
    dataType: "string",
    name: "input",
    label: "文本输入",
    placeholder: "请输入文本内容",
    options: [],
    getData: () => { },
    data: "",
    span: 24,
    disable: false,
    required: false,
    verifyRegex: "",
    verifyErrMsg: "请输入input",
    isMouseenter: false,
    isSelected: true,
    isDragging: false
}])

let selectedFormItem: formItemDataType = {
    id: -1,
    type: "",
    dataType: "",
    name: "",
    label: "",
    placeholder: "",
    getData: () => { },
    data: "",
    span: 24,
    disable: false,
    required: false,
    verifyRegex: "",
    verifyErrMsg: "",
    isMouseenter: false,
    isSelected: false,
    isDragging: false
}

let addComponentFlag = false
const formPreviewVisiable = ref<boolean>(false)
const codePreviewVisiable = ref<boolean>(false)

function componentMousedown() {
    for (let i = 0; i < formItemList.length; i++) {
        formItemList[i].isDragging = false
        formItemList[i].isMouseenter = false
        formItemList[i].isSelected = false
    }
}

function componentDragstart(component: any) {
    addComponentFlag = true
    selectedFormItem = {
        ...component.defaultData
    }
    selectedFormItem.id = formItemList.length
    selectedFormItem.name = selectedFormItem.name + formItemList.length
}

function componentDragend() {
    for (let i = 0; i < formItemList.length; i++) {
        formItemList[i].isDragging = false
        formItemList[i].isMouseenter = false
    }
}

function formPreviewDragenter() {
    if (formItemList.length === 0) {
        formItemList.push(selectedFormItem)
    }
}

function mouseenterHandler(item: any) {
    item.isMouseenter = true
}

function mouseleaveHandler(item: any) {
    item.isMouseenter = false
}

function mousedownHandler(item: any) {
    for (let i = 0; i < formItemList.length; i++) {
        formItemList[i].isSelected = false
    }
    selectedFormItem = item
    item.isSelected = true
    item.isDragging = true
    addComponentFlag = false
}

function mouseupHandler(item: any) {
    item.isDragging = false
}

function dragenterHandler(event: DragEvent, item: any) {
    if (addComponentFlag) {
        const oldIndex = formItemList.indexOf(selectedFormItem)
        const newIndex = formItemList.indexOf(item)
        if (newIndex === formItemList.length && event.offsetY > 39) {
            if (oldIndex !== -1) {
                formItemList.splice(oldIndex, 1)
            }
            formItemList.push(selectedFormItem)
        } else {
            if (event.offsetY <= 39) {
                if (oldIndex !== -1) {
                    formItemList.splice(oldIndex, 1)
                }
                formItemList.splice(newIndex, 0, selectedFormItem)
            } else {
                if (oldIndex !== -1) {
                    formItemList.splice(oldIndex, 1)
                }
                formItemList.splice(newIndex + 1, 0, selectedFormItem)
            }
        }
    } else {
        if (item !== selectedFormItem) {
            const oldIndex = formItemList.indexOf(selectedFormItem)
            const newIndex = formItemList.indexOf(item)
            formItemList.splice(oldIndex, 1)
            formItemList.splice(newIndex, 0, selectedFormItem)
        }
    }
}

function dragendHandler(item: any) {
    for (let i = 0; i < formItemList.length; i++) {
        formItemList[i].isDragging = false
    }
}

function copyItem(item: any) {
    const newItem = { ...item }
    newItem.isMouseenter = false
    newItem.isSelected = false
    newItem.isDragging = false
    newItem.id = formItemList.length
    formItemList.push(newItem)
}

function deleteItem(item: any) {
    formItemList.splice(formItemList.indexOf(item), 1)
}

const formPreviewCode = ref("")

function openCodePreview() {
    codePreviewVisiable.value = true
    const request = {
        formConfig: formConfig,
        formItemList: formItemList
    }
    http.post("/form/code/preview", request).then(({ data }) => {
        if (data.code === "0") {
            formPreviewCode.value = data.data
        }
    })
}

function copyCode() {
    const request = {
        formConfig: formConfig,
        formItemList: formItemList
    }
    http.post("/form/code/download", request, {
        responseType: 'blob'
    }).then(({ headers, data }) => {
        let filename = "file"
        if (headers['content-disposition']) {
            filename = headers['content-disposition'].replace(/attachment; filename=(.*)/, '$1')
        }
        const blob = new Blob([data], { type: headers['content-type'] })
        let dom = document.createElement('a')
        let url = window.URL.createObjectURL(blob)
        dom.href = url
        dom.download = decodeURI(filename)
        dom.style.display = 'none'
        document.body.appendChild(dom)
        dom.click()
        if (dom.parentNode) {
            dom.parentNode.removeChild(dom)
        }
        window.URL.revokeObjectURL(url)
        notification['success']({
            content: '下载成功',
            meta: `文件下载成功`,
            duration: 2500,
            keepAliveOnHover: true
        })
    })
}
</script>

<template>
    <div class="flame-container">
        <n-card :bordered="false"
            :header-style="{ paddingTop: '12px', paddingBottom: '8px', borderBottom: '1px solid var(--n-border-color)' }"
            :content-style="{
                display: 'flex', padding: '0px', overflowY: 'auto', transition: 'border-color .3s var(--n-bezier)'
            }">
            <template #header>
                <n-space justify="space-between">
                    <div style="font-size:18px;font-weight: 400;height: 34px;line-height: 34px;">
                        表单设计
                    </div>
                    <div>
                        <n-button quaternary @click="formPreviewVisiable = true">预览表单</n-button>
                        <n-button quaternary @click="openCodePreview">查看代码</n-button>
                        <n-button quaternary @click="formItemList.length = 0">清空</n-button>
                    </div>
                </n-space>
            </template>
            <div class="form-component">
                <div v-for="group in componentGroupList" :key="group.name" class="component-group">
                    <div class="title">{{ group.name }}</div>
                    <div class="component-list">
                        <n-tag v-for="component in group.componentList" :key="component.name" draggable="true"
                            @mousedown="componentMousedown" @dragstart="componentDragstart(component)"
                            @dragend="componentDragend" class="component">
                            {{ component.name }} </n-tag>
                    </div>
                </div>
            </div>
            <div class="form-preview" @dragenter="formPreviewDragenter">
                <n-form :size="formConfig.size" :label-align="formConfig.labelAlign"
                    :label-placement="formConfig.labelPlacement" :label-width="formConfig.labelWidth"
                    require-mark-placement="left">
                    <n-grid :cols="24" :x-gap="formConfig.xGap">
                        <n-form-item-gi v-for="item in formItemList" :key="item.id" :span="item.span" :label="item.label"
                            :path="item.name" :show-require-mark="item.required"
                            :class="['form-item-wrap', { 'selected': item.isSelected }, { 'dragging': item.isDragging }]"
                            :draggable="item.isDragging" @mousedown="mousedownHandler(item)" @mouseup="mouseupHandler(item)"
                            @mouseenter="mouseenterHandler(item)" @mouseleave="mouseleaveHandler(item)"
                            @dragenter="dragenterHandler($event, item)" @dragend="dragendHandler(item)">
                            <n-input v-if="item.type === 'input'" v-model:value="item.data" :disabled="item.disable"
                                :placeholder="item.placeholder" clearable />
                            <n-input-number v-if="item.type === 'input-number'" v-model:value="item.data"
                                :disabled="item.disable" :placeholder="item.placeholder" style="width:100%" />
                            <n-mention v-if="item.type === 'montion'" v-model:value="item.data" :options="item.options"
                                :disabled="item.disable" default-value="@" :placeholder="item.placeholder" clearable />
                            <n-auto-complete v-if="item.type === 'auto-complete'" v-model:value="item.data"
                                :disabled="item.disable" :options="item.getData(item.data)" :placeholder="item.placeholder"
                                clearable />
                            <n-dynamic-input v-if="item.type === 'dynamic-input'" v-model:value="item.data"
                                :disabled="item.disable" :placeholder="item.placeholder" />
                            <n-dynamic-tags v-if="item.type === 'dynamic-tags'" v-model:value="item.data"
                                :disabled="item.disable" />
                            <n-select v-if="item.type === 'select'" v-model:value="item.data" :options="item.options"
                                :disabled="item.disable" :placeholder="item.placeholder" />
                            <n-tree-select v-if="item.type === 'tree-select'" :options="item.options" key-field="value"
                                :disabled="item.disable" v-model:value="item.data" :placeholder="item.placeholder" />
                            <n-cascader v-if="item.type === 'cascader'" v-model:value="item.data" :disabled="item.disable"
                                :options="item.options" :show-path="true" :placeholder="item.placeholder" />
                            <n-switch v-if="item.type === 'switch'" v-model:value="item.data" :disabled="item.disable" />
                            <n-checkbox v-if="item.type === 'checkbox'" v-model:checked="item.data"
                                :disabled="item.disable" />
                            <n-radio v-if="item.type === 'radio'" v-model:checked="item.data" :disabled="item.disable" />
                            <n-checkbox-group v-if="item.type === 'checkbox-group'" v-model:value="item.data"
                                :disabled="item.disable">
                                <n-space item-style="display: flex;">
                                    <n-checkbox v-for="option in item.options" :label="option.label"
                                        :value="option.value" />
                                </n-space>
                            </n-checkbox-group>
                            <n-radio-group v-if="item.type === 'radio-group'" v-model:value="item.data"
                                :disabled="item.disable" name="radiogroup">
                                <n-space>
                                    <n-radio v-for="option in item.options" :key="option.value" :label="option.label"
                                        :value="option.value" />
                                </n-space>
                            </n-radio-group>
                            <n-date-picker style="width: 100%" v-if="item.type === 'date-picker'"
                                :placeholder="item.placeholder" v-model:formatted-value="item.data" :disabled="item.disable"
                                type="date" value-format="yyyy-MM-dd" clearable />
                            <n-time-picker style="width: 100%" v-if="item.type === 'time-picker'"
                                :placeholder="item.placeholder" v-model:formatted-value="item.data" :disabled="item.disable"
                                value-format="HH:mm:ss" clearable />
                            <n-slider v-if="item.type === 'slider'" v-model:value="item.data" :disabled="item.disable" />
                            <n-transfer v-if="item.type === 'transfer'" v-model:value="item.data" :disabled="item.disable"
                                :options="item.options" />
                            <n-rate v-if="item.type === 'rate'" v-model:value="item.data" allow-half
                                :disabled="item.disable" />
                            <n-color-picker v-if="item.type === 'color-picker'" v-model:value="item.data"
                                :disabled="item.disable" :modes="['hex']" />
                            <n-upload v-if="item.type === 'upload'" :disabled="item.disable">
                                <n-button>上传文件</n-button>
                            </n-upload>
                            <n-button v-if="item.type === 'button'" :disabled="item.disable">{{ item.label }}</n-button>

                            <n-button v-if="item.isMouseenter || item.isSelected" @click="copyItem(item)" class="copy-btn"
                                type="primary" size="small" tertiary circle>
                                <template #icon>
                                    <n-icon>
                                        <CopyOutlined />
                                    </n-icon>
                                </template>
                            </n-button>
                            <n-button v-if="item.isMouseenter || item.isSelected" @click="deleteItem(item)"
                                class="delete-btn" type="error" size="small" tertiary circle>
                                <template #icon>
                                    <n-icon>
                                        <DeleteOutlined />
                                    </n-icon>
                                </template>
                            </n-button>
                        </n-form-item-gi>
                    </n-grid>
                </n-form>
            </div>
            <div class="form-attribute">
                <n-tabs type="segment">
                    <n-tab-pane name="chap1" tab="组件属性">
                        <div v-for="formItem in formItemList" :key="formItem.id">
                            <n-form v-if="formItem.isSelected" style="padding: 0 5px" label-placement="left"
                                label-width="68px">
                                <n-form-item label="字段名">
                                    <n-input v-model:value="formItem.name" placeholder="请输入字段名" clearable />
                                </n-form-item>
                                <n-form-item label="标题">
                                    <n-input v-model:value="formItem.label" placeholder="请输入标题" clearable />
                                </n-form-item>
                                <n-form-item label="占位提示">
                                    <n-input v-model:value="formItem.placeholder" placeholder="请输入占位提示" clearable />
                                </n-form-item>
                                <n-form-item label="栅格">
                                    <n-slider v-model:value="formItem.span" :min="1" :max="24" :step="1" />
                                </n-form-item>
                                <n-form-item label="是否禁用">
                                    <n-switch v-model:value="formItem.disable" />
                                </n-form-item>
                                <n-form-item label="是否必填">
                                    <n-switch v-model:value="formItem.required" />
                                </n-form-item>
                                <n-divider
                                    v-if="',montion,select,checkbox-group,radio-group,transfer'.search(formItem.type) > 0"
                                    style="margin-top:0">
                                    选项
                                </n-divider>
                                <n-form-item
                                    v-if="',montion,select,checkbox-group,radio-group,transfer'.search(formItem.type) > 0">
                                    <n-dynamic-input v-model:value="formItem.options"
                                        :on-create="() => { return { label: '', value: '' } }">
                                        <template #default="{ value }">
                                            <n-space>
                                                <n-input v-model:value="value.label" placeholder="请输入选项名" type="text"
                                                    clearable />
                                                <n-input v-model:value="value.value" placeholder="请输入选项值" type="text"
                                                    clearable />
                                            </n-space>
                                        </template>
                                    </n-dynamic-input>
                                </n-form-item>
                                <n-divider v-if="',input,input-number,montion,auto-complete'.search(formItem.type) > 0"
                                    style="margin-top:0">
                                    正则校验
                                </n-divider>
                                <n-form-item v-if="',input,input-number,montion,auto-complete'.search(formItem.type) > 0"
                                    label="表达式">
                                    <n-input v-model:value="formItem.verifyRegex" placeholder="请输入正则表达式" clearable />
                                </n-form-item>
                                <n-form-item label="异常提示">
                                    <n-input v-model:value="formItem.verifyErrMsg" placeholder="请输入异常提示信息" clearable />
                                </n-form-item>
                            </n-form>
                        </div>
                    </n-tab-pane>
                    <n-tab-pane name="chap2" tab="表单属性">
                        <n-form style="padding: 0 5px" :model="formConfig" label-placement="left">
                            <n-form-item label="表单标题" path="title">
                                <n-input v-model:value="formConfig.title" clearable />
                            </n-form-item>
                            <n-form-item label="表单宽度" path="width">
                                <n-input-number v-model:value="formConfig.width" clearable />
                            </n-form-item>
                            <n-form-item label="表单模型" path="model">
                                <n-input v-model:value="formConfig.model" clearable />
                            </n-form-item>
                            <n-form-item label="校验规则" path="rules">
                                <n-input v-model:value="formConfig.rules" clearable />
                            </n-form-item>
                            <n-form-item label="表单尺寸" path="size">
                                <n-radio-group v-model:value="formConfig.size" name="size">
                                    <n-radio-button label="大" value="large" />
                                    <n-radio-button label="中" value="medium" />
                                    <n-radio-button label="小" value="small" />
                                </n-radio-group>
                            </n-form-item>
                            <n-form-item label="标签对齐" path="labelAlign">
                                <n-radio-group v-model:value="formConfig.labelAlign" name="labelAlign">
                                    <n-radio-button label="左" value="left" />
                                    <n-radio-button label="右" value="right" />
                                </n-radio-group>
                            </n-form-item>
                            <n-form-item label="标签位置" path="labelPlacement">
                                <n-radio-group v-model:value="formConfig.labelPlacement" name="labelPlacement">
                                    <n-radio-button label="左" value="left" />
                                    <n-radio-button label="上" value="top" />
                                </n-radio-group>
                            </n-form-item>
                            <n-form-item label="标签长度" path="labelWidth">
                                <n-input-number v-model:value="formConfig.labelWidth" :min="0" />
                            </n-form-item>
                            <n-form-item label="栅格间隔" path="xGap">
                                <n-input-number v-model:value="formConfig.xGap" :min="0" />
                            </n-form-item>
                        </n-form>
                    </n-tab-pane>
                </n-tabs>
            </div>
        </n-card>
    </div>

    <n-modal v-model:show="formPreviewVisiable">
        <n-card :style="{ width: formConfig.width + 'px' }" :title="formConfig.title" :size="formConfig.size">
            <n-form :size="formConfig.size" :label-align="formConfig.labelAlign"
                :label-placement="formConfig.labelPlacement" :label-width="formConfig.labelWidth"
                require-mark-placement="left">
                <n-grid :cols="24" :x-gap="formConfig.xGap">
                    <n-form-item-gi v-for="item in formItemList" :key="item.id" :span="item.span" :label="item.label"
                        :path="item.name" :show-require-mark="item.required">
                        <n-input v-if="item.type === 'input'" v-model:value="item.data" :disabled="item.disable"
                            :placeholder="item.placeholder" clearable />
                        <n-input-number v-if="item.type === 'input-number'" v-model:value="item.data"
                            :disabled="item.disable" :placeholder="item.placeholder" style="width:100%" />
                        <n-mention v-if="item.type === 'montion'" v-model:value="item.data" :options="item.options"
                            :disabled="item.disable" default-value="@" :placeholder="item.placeholder" clearable />
                        <n-auto-complete v-if="item.type === 'auto-complete'" v-model:value="item.data"
                            :disabled="item.disable" :options="item.getData(item.data)" :placeholder="item.placeholder"
                            clearable />
                        <n-dynamic-input v-if="item.type === 'dynamic-input'" v-model:value="item.data"
                            :disabled="item.disable" :placeholder="item.placeholder" />
                        <n-dynamic-tags v-if="item.type === 'dynamic-tags'" v-model:value="item.data"
                            :disabled="item.disable" />
                        <n-select v-if="item.type === 'select'" v-model:value="item.data" :options="item.options"
                            :disabled="item.disable" :placeholder="item.placeholder" />
                        <n-tree-select v-if="item.type === 'tree-select'" :options="item.options" :disabled="item.disable"
                            :default-value="item.data" :placeholder="item.placeholder"
                            @update:value="(value) => item.data = value" />
                        <n-cascader v-if="item.type === 'cascader'" v-model:value="item.data" :disabled="item.disable"
                            :options="item.options" :show-path="true" :placeholder="item.placeholder" />
                        <n-switch v-if="item.type === 'switch'" v-model:value="item.data" :disabled="item.disable" />
                        <n-checkbox v-if="item.type === 'checkbox'" v-model:checked="item.data" :disabled="item.disable" />
                        <n-radio v-if="item.type === 'radio'" v-model:checked="item.data" :disabled="item.disable" />
                        <n-checkbox-group v-if="item.type === 'checkbox-group'" v-model:value="item.data"
                            :disabled="item.disable">
                            <n-space item-style="display: flex;">
                                <n-checkbox v-for="option in item.options" :label="option.label" :value="option.value" />
                            </n-space>
                        </n-checkbox-group>
                        <n-radio-group v-if="item.type === 'radio-group'" v-model:value="item.data" :disabled="item.disable"
                            name="radiogroup">
                            <n-space>
                                <n-radio v-for="option in item.options" :key="option.value" :label="option.label"
                                    :value="option.value" />
                            </n-space>
                        </n-radio-group>
                        <n-date-picker style="width: 100%" v-if="item.type === 'date-picker'"
                            :placeholder="item.placeholder" v-model:formatted-value="item.data" :disabled="item.disable"
                            type="date" value-format="yyyy-MM-dd" clearable />
                        <n-time-picker style="width: 100%" v-if="item.type === 'time-picker'"
                            :placeholder="item.placeholder" v-model:formatted-value="item.data" :disabled="item.disable"
                            value-format="HH:mm:ss" clearable />
                        <n-slider v-if="item.type === 'slider'" v-model:value="item.data" :disabled="item.disable" />
                        <n-transfer v-if="item.type === 'transfer'" v-model:value="item.data" :disabled="item.disable"
                            :options="item.options" />
                        <n-rate v-if="item.type === 'rate'" v-model:value="item.data" allow-half :disabled="item.disable" />
                        <n-color-picker v-if="item.type === 'color-picker'" v-model:value="item.data"
                            :disabled="item.disable" :modes="['hex']" />
                        <n-upload v-if="item.type === 'upload'" :disabled="item.disable">
                            <n-button>上传文件</n-button>
                        </n-upload>
                        <n-button v-if="item.type === 'button'" :disabled="item.disable">{{ item.label }}</n-button>
                    </n-form-item-gi>
                </n-grid>
            </n-form>
            <template #footer>
                <n-space justify="end">
                    <n-button @click="formPreviewVisiable = false">取消</n-button>
                    <n-button @click="formPreviewVisiable = false">提交</n-button>
                </n-space>
            </template>
        </n-card>
    </n-modal>
    <n-modal v-model:show="codePreviewVisiable">
        <n-card style="width:100%">
            <template #header>
                <n-space justify="space-between">
                    <div>
                        表单代码
                    </div>
                    <div>
                        <n-button quaternary @click="copyCode()">下载</n-button>
                        <n-button quaternary @click="codePreviewVisiable = false">关闭</n-button>
                    </div>
                </n-space>
            </template>
            <n-text style="white-space: pre;">{{ formPreviewCode }}</n-text>
        </n-card>
    </n-modal>
</template>

<style scoped>
.form-component {
    width: 260px;
    border-right: 1px solid var(--n-border-color);
    transition: border-color .3s var(--n-bezier);
    overflow-y: auto;
}

.form-component .component-group {
    display: flex;
    flex-direction: column;
    padding: 0 1px;
    margin: 2px 0px 25px 0px;
}

.form-component .component-group .title {
    height: 35px;
    line-height: 35px;
    padding-left: 5px;
    font-size: 15px;
}

.form-component .component-group .component-list {
    display: grid;
    grid-template-columns: repeat(2, 123px);
    justify-content: space-around;
    grid-auto-rows: 35px;
}

.form-component .component-group .component-list .component {
    height: 30px;
}

.form-component .component-group .component-list .component:hover {
    cursor: move;
}

.form-preview {
    flex: 1;
    padding: 0 5px;
    overflow-y: auto;
}

.form-preview .form-item-wrap {
    position: relative;
    margin-top: 9px;
    padding-top: 14px;
    box-sizing: border-box;
    border-top: 5px solid var(--n-color);
    border-left: 1px solid var(--n-color);
    border-bottom: 1px solid var(--n-color);
    border-right: 1px solid var(--n-color);
    transition: border-color .3s var(--n-bezier);
}

.form-preview .selected {
    background-color: var(--flame-primary-color-transparent);
}

.form-preview .dragging {
    border-top: 5px solid var(--flame-primary-color);
    border-left: 1px dashed var(--flame-primary-color-transparent);
    border-bottom: 1px dashed var(--flame-primary-color-transparent);
    border-right: 1px dashed var(--flame-primary-color-transparent);
    background-color: var(--flame-primary-color-transparent);
}

.form-preview .form-item-wrap:hover {
    cursor: move;
    background-color: var(--flame-primary-color-transparent);
}

.form-preview .form-item-wrap .copy-btn {
    position: absolute;
    top: -28px;
    right: 48px;
}

.form-preview .form-item-wrap .delete-btn {
    position: absolute;
    top: -28px;
    right: 10px;
}

.form-attribute {
    width: 300px;
    border-left: 1px solid var(--n-border-color);
    transition: border-color .3s var(--n-bezier);
    overflow-y: auto;
}
</style>